package mars;

/**
 *
 * @author Eduardo Freire
 */
public class LineIntegralConvolution {
    public static final int X = 0;
    public static final int Y = 1;

    private int L = 20;
    private float ds = 0.5f;
    private float vectorField[][][];
    private int[][] pixels;
    private int width;
    private int height;
    private float min = Float.MAX_VALUE;
    private float max = -Float.MAX_VALUE;



    public LineIntegralConvolution(int[][] pixels, int width, int height, float[][][] vectorField) throws Exception {
        this.vectorField = vectorField;
        this.width = width;
        this.height = height;
        this.pixels = pixels;
    }

    public Float [][] getFlow() {
        Float pixelsOut[][] = new Float[width][height];
        float conv;

        for(int i = 0; i < width; i++) {
            for(int j = 0; j < height; j++) {
                conv = convolution(i, j);

                if(conv < min) min = conv;
                else if(conv > max) max = conv;

                pixelsOut[i][j] = conv;
            }
        }

        return pixelsOut;
    }

    private float convolution(int x0, int y0) {
        float[] v1 = vectorField[x0][y0];
        float[] v2 = v1;
        float x1 = x0;
        float y1 = y0;
        float x2 = x0;
        float y2 = y0;
        float sum = getPixelValue(x0, y0);

//        System.out.println("float[] v1 = vectorField[x0][y0]; " + v1[0] + " | " + v1[1]);
//        System.out.println("Sum = " + sum);

        for(int s = 0; s < L; s++) {
            x1 = x1 + ds*v1[X];
            y1 = y1 + ds*v1[Y];
            x2 = x2 - ds*v2[X];
            y2 = y2 - ds*v2[Y];

//          System.out.println("Interacao " + s);
//            System.out.println("X1 = " + x1);
//            System.out.println("Y1 = " + y1);
//            System.out.println("X2 = " + x2);
//            System.out.println("Y2 = " + y2);

            if(x1 >= 0 && y1 >= 0 && x1 < width && y1 < height) {
                v1 = getVector(x1, y1, v1);
            }
            if(x2 >= 0 && y2 >= 0 && x2 < width && y2 < height) {
                v2 = getVector(x2, y2, v2);
            }

            sum += getPixelValue(x1, y1);
            sum += getPixelValue(x2, y2);

//            System.out.println("SUM " + sum);
//            System.out.println("-------------------\n");
        }

//        System.out.println("SUM FINAL " + sum);

//        System.out.println("(2*L + 1) = " + (2*L + 1));
//        System.out.println("Final = " + (sum / (2*L + 1)));

        return sum / (2*L + 1);
    }

    private float[] getVector(float x, float y, float[] v) {
        float[] v1 = vectorField[(int)x][(int)y];

        if(v[X]*v1[X] + v[Y]*v1[Y] < 0) {
            v1[X] = -v1[X];
            v1[Y] = -v1[Y];
        }

        return v1;
    }

    private float getPixelValue(float x, float y) {
        x = Math.abs(x) % width;
        y = Math.abs(y) % height;

        int i = (int)x;
        int j = (int)y;
        int i1 = (i + 1) % width;
        int j1 = (j + 1) % height;

//        System.out.println("Antes : " + x + "|" + y + "|" + i + "|" + j + "|" + i1 + "|" + j1 + "|");
//
//        System.out.println("pixels[i][j] = " + pixels[i][j]);
//        System.out.println("pixels[i][j1] = " + pixels[i][j1]);
//        System.out.println("pixels[i][j1] - pixels[i][j] = " + (pixels[i][j1] - pixels[i][j]));
//        System.out.println("y - j = " + (y - j));
        

        float f_iy = pixels[i][j] + (y - j)*(pixels[i][j1] - pixels[i][j]);


//        System.out.println("pixels[i1][j] = " + pixels[i1][j]);
//        System.out.println("pixels[i1][j1] = " + pixels[i1][j1]);
//        System.out.println("pixels[i1][j1] - pixels[i1][j] = " + (pixels[i1][j1] - pixels[i1][j]));
//        System.out.println("y - j = " + (y-j));
        
        float f_i1y = pixels[i1][j] + (y - j)*(pixels[i1][j1] - pixels[i1][j]);


//        System.out.println("Antes2 " + f_iy + "|" + f_i1y);

        return f_iy + (x - i)*(f_i1y - f_iy);
    }

    public float getMax() {
        return max;
    }

    public float getMin() {
        return min;
    }

    public void startTest() {
        //float [] f = getVector(1.6, 0.6, vectorField[0][0]);
        //System.out.println("Final Vector " + f[0] + " _ " + f[1]);
        
        //System.out.println("FInal: " + getPixelValue(2.7, 3.9));
        //System.out.println("Teste " + convolution(3, 3));
    }
}
